package tech.waterism.topo.handler;

import lombok.extern.slf4j.Slf4j;
import tech.waterism.topo.context.CalculationContext;
import tech.waterism.topo.model.*;

import java.util.*;

/**
 * 联合调度处理器
 * 
 * <p>处理多水库/蓄滞洪区联合调度
 * 
 * <h3>核心职责：</h3>
 * <ul>
 *   <li>判断联调触发条件</li>
 *   <li>初始化联调节点</li>
 *   <li>协调联调计算</li>
 *   <li>合并联调结果</li>
 * </ul>
 * 
 * <h3>联调触发条件：</h3>
 * <p>当联调组的所有上游起点节点都计算完成时，触发该联调组的计算
 * 
 * @author waterism
 * @since 1.0.0
 */
@Slf4j
public class JointDispatchHandler {
    
    /**
     * 判断是否触发联调
     * <p>遍历所有联调组，检查是否有组的所有上游节点都已计算完成
     * 
     * @param context 计算上下文
     * @return true表示有联调组被触发
     */
    public boolean shouldTrigger(CalculationContext context) {
        List<JointDispatchGroup> groups = context.getJointGroups();
        if (groups == null || groups.isEmpty()) {
            return false;
        }
        
        for (JointDispatchGroup group : groups) {
            if (group.allUpstreamCalculated(context)) {
                log.info("触发联调组 {} ({})", group.getJmsid(), group.getName());
                context.setTriggeredGroup(group.getJmsid());
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 获取联调起点位置
     * <p>找到上游起点节点中最早出现的位置，作为回溯点
     * 
     * @param group 联调组
     * @param context 计算上下文
     * @return 最小的节点索引位置
     */
    public int getBacktrackPosition(JointDispatchGroup group, CalculationContext context) {
        List<String> upstreamNodes = group.getUpstreamNodes();
        if (upstreamNodes == null || upstreamNodes.isEmpty()) {
            return 0;
        }
        
        int minIndex = Integer.MAX_VALUE;
        for (String stcd : upstreamNodes) {
            Integer index = context.getNodeIndex(stcd);
            if (index != null && index < minIndex) {
                minIndex = index;
            }
        }
        
        return minIndex == Integer.MAX_VALUE ? 0 : minIndex;
    }
    
    /**
     * 初始化联调节点
     * <p>将上游起点节点的计算结果复用到联调节点中
     * 
     * @param group 联调组
     * @param context 计算上下文
     */
    public void initializeUpstreamNodes(JointDispatchGroup group, CalculationContext context) {
        List<String> upstreamNodes = group.getUpstreamNodes();
        if (upstreamNodes == null || upstreamNodes.isEmpty()) {
            return;
        }
        
        // 遍历联调节点，找到上游起点节点，复用其计算结果
        for (TopoNode node : group.getNodes()) {
            if (upstreamNodes.contains(node.getStcd())) {
                // 从主缓存获取已计算的结果
                NodeResult cachedResult = context.getCachedResult(node.getStcd());
                if (cachedResult != null) {
                    // 复用数据
                    node.setData(cachedResult.getData());
                    log.debug("联调节点 {} 复用主缓存结果", node.getStcd());
                }
            }
        }
    }
    
    /**
     * 检查是否需要计算排洪
     * <p>如果下游有蓄滞洪区（STORE类型），则需要计算排洪
     * 
     * @param node 当前节点
     * @return true表示需要计算排洪
     */
    public boolean needCalculateDischarge(TopoNode node) {
        if (node.getInputs() == null) {
            return false;
        }
        
        for (InputComponent input : node.getInputs()) {
            if ("STORE".equals(input.getArtp()) || "X".equals(input.getArtp())) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 累加联调节点的QPrep（蓄滞洪区专用）
     * 
     * @param node 拓扑节点
     * @param inputs 输入分量列表
     */
    public void sumQPrep(TopoNode node, List<InputComponent> inputs) {
        List<TimeSeriesData> nodeData = node.getData();
        
        // 初始化QPrep为0
        for (TimeSeriesData data : nodeData) {
            if (data.getQPrep() == null) {
                data.setQPrep(0.0);
            }
        }
        
        // 累加所有输入分量的QPrep
        for (InputComponent input : inputs) {
            List<TimeSeriesData> inputData = input.getData();
            for (int i = 0; i < nodeData.size() && i < inputData.size(); i++) {
                Double inputQPrep = Optional.ofNullable(inputData.get(i).getQPrep()).orElse(0.0);
                nodeData.get(i).addQPrep(inputQPrep);
            }
        }
    }
    
    /**
     * 从联调缓存获取上游数据
     * 
     * @param input 输入分量
     * @param context 计算上下文
     * @return 上游节点结果，不存在则返回null
     */
    public NodeResult getUpstreamFromJointCache(InputComponent input, CalculationContext context) {
        String arcd = input.getArcd();
        // 优先从联调缓存获取
        NodeResult result = context.getJointResultCache().get(arcd);
        if (result != null) {
            return result;
        }
        // 如果联调缓存没有，从主缓存获取
        return context.getCachedResult(arcd);
    }
}

